//
//  NiloGroup
//
//  Created by Nils Iver Holtar on 2012-10-26.
//  Copyright (c) 2012 . All rights reserved.
//

package {
	import org.flixel.*;
	public class NiloGroup extends FlxGroup {
		
		protected var _refobj:FlxSprite;
		private var _offsets:Object;
		private var _lastID:uint;
		private var _colliderGroup:FlxGroup;
		private var _colliders:Array;
		private var _fadeTime:Number;
		private var _fadeTimeTotal:Number;
		private var _targetAlpha:Number;
		private var _alphaDifference:Number;
		private var _lastAlpha:Number;
		private var _alpha:Number;
		
		public var width:Number, height:Number;
		
		public function NiloGroup(X:Number = 0, Y:Number = 0, Width:Number = 0, Height:Number = 0){
			super(20);
			width = Width;
			height = Height;
			_refobj = new FlxSprite(X, Y);
			//_refobj.makeGraphic(Width, Height);
			_offsets = {};
			_lastID = 0;
			_colliders = [];
			_targetAlpha = 1.0;
			_fadeTime = 0.0;
			_fadeTimeTotal = 0.0;
			_lastAlpha = 1.0;
			_alpha = 1.0;
			_alphaDifference = 0.0;
		}
		
		public function setColliderGroup(colliderGroupARG:FlxGroup):NiloGroup {
			if (_colliderGroup == null){
				_colliderGroup = colliderGroupARG;
				setupColliders();	
			}
			else {
				for each (var obj:FlxBasic in _colliders){
					colliderGroupARG.add(obj);
				}
				_colliderGroup = colliderGroupARG;
			}
			return this;
		}
		
		/*
		 * Override in subclass
		 */
		protected function setupColliders():void {	
		}
		
		private function getOffset(id:uint):FlxPoint {
			return _offsets[id] as FlxPoint;
		}
		
		public function reposition(object:FlxBasic, X:Number, Y:Number):FlxBasic{
			if (object is FlxObject || object is NiloGroup)
				_offsets[object.ID] = new FlxPoint(X, Y);
			return object;
		}
		
		override public function add(object:FlxBasic):FlxBasic{
			if (object is FlxObject){
				var obj:FlxObject = object as FlxObject;
				obj.ID = _lastID;
				_offsets[obj.ID] = new FlxPoint(obj.x, obj.y);
				obj.x = obj.x + this.x;
				obj.y = obj.y + this.y;
				_lastID++;
			}
			else if (object is NiloGroup){
				var group:NiloGroup = object as NiloGroup;
				group.ID = _lastID;
				_offsets[group.ID] = new FlxPoint(group.x, group.y);
				group.x = group.x + this.x;
				group.y = group.y + this.y;
				_lastID++;
			}
			return super.add(object);
		}
		
		public function addCollider(object:Collider):Collider{
			if (_colliderGroup != null) {
				object.parent = this;
				_colliderGroup.add(object);
				add(object);
				_colliders.push(object);
			}
			return object;
		}
		
		public function removeCollider(object:Collider):Collider{
			if (_colliderGroup != null) {
				object.kill();
				_colliderGroup.remove(object, true);
				_colliders.splice(_colliders.indexOf(object));
			}
			return object;
		}
		
		override public function remove(object:FlxBasic, splice:Boolean = false):FlxBasic{
			if (object is FlxObject){
				var obj:FlxObject = object as FlxObject;
				delete _offsets[obj.ID];
			}
			return super.remove(object, splice);
		}
		
		override public function preUpdate():void {
			_refobj.preUpdate();
			super.preUpdate();
		}
		
		override public function postUpdate():void {
			_refobj.postUpdate();
			super.postUpdate();
		}
		
		override public function update():void {
			_refobj.update();
			var currentAlpha:Number = _alpha;
			if (_fadeTime < _fadeTimeTotal && _fadeTimeTotal != 0){
				_fadeTime += FlxG.elapsed;
				if (_fadeTime > _fadeTimeTotal) _fadeTime = _fadeTimeTotal;
				var ratio:Number = _fadeTime / _fadeTimeTotal;
				currentAlpha = _lastAlpha + (_alphaDifference * ratio);
			}
			for (var i:uint = 0; i < members.length; i++){
				if (members[i]){
					if (members[i] is FlxObject){
						var flxObject:FlxObject = members[i] as FlxObject;
						flxObject.x = _refobj.x + getOffset(flxObject.ID).x;
						flxObject.y = _refobj.y + getOffset(flxObject.ID).y;
						if (flxObject is FlxSprite){
							(flxObject as FlxSprite).alpha = currentAlpha;
						}
						
					}
					else if(members[i] is NiloGroup){
						var niloGroup:NiloGroup = members[i] as NiloGroup;
						niloGroup.x = _refobj.x + getOffset(niloGroup.ID).x;
						niloGroup.y = _refobj.y + getOffset(niloGroup.ID).y;
					}
				}
				
			}
			super.update();
		}
		
		override public function destroy():void {
			super.destroy();
			_refobj.destroy();
			_lastID = 0;
			_offsets = {};
		}
		
		public function collided(ownCollider:Collider, object:FlxObject):void {
			
		}
		
		public function collidedWithCollider(ownCollider:Collider, collider:Collider):void{
			/*
			if (collider.uniqueID == "wall" && ownCollider.uniqueID == "base"){
				//bounce:
				bounce(ownCollider, collider, 10);
			}
			*/
			 
		}
		
		public function colliderOutOfBounds(ownCollider:Collider):void{
			
		}
		
		public function bounce(ownCollider:Collider, collider:FlxObject, minVeloValue:Number = 0):void{
			var leftValue:Number = Math.abs((ownCollider.x + ownCollider.width) - collider.x);
			var rightValue:Number = Math.abs(ownCollider.x - (collider.x + collider.width));
			var topValue:Number = Math.abs((ownCollider.y + ownCollider.height) - collider.y);
			var bottomValue:Number = Math.abs(ownCollider.y - (collider.y + collider.height));
			var smallest:Number = Math.min(leftValue, rightValue, topValue, bottomValue);
			var forceX:int = 0, forceY:int = 0;
			if (leftValue == smallest){
				velocity.x = Math.abs(velocity.x) * -1;
				forceX = -1;
			}
			else if (rightValue == smallest){
				velocity.x = Math.abs(velocity.x);
				forceX = 1;
			}
			if (topValue == smallest){
				velocity.y = Math.abs(velocity.y) * -1;	
				forceY = -1;
			}
			else if (bottomValue == smallest){
				velocity.y = Math.abs(velocity.y);
				forceY = 1;
			}
			if (forceX != 0){
				if (Math.abs(velocity.x) < minVeloValue){
					if (velocity.x == 0) velocity.x = minVeloValue * forceX; 
					else velocity.x = minVeloValue * (velocity.x / Math.abs(velocity.x));
				}
			}
			if (forceY != 0){
				if (Math.abs(velocity.y) < minVeloValue){
					if (velocity.y == 0) velocity.y = minVeloValue * forceY;
					else velocity.y = minVeloValue * (velocity.y / Math.abs(velocity.y));
				}
			}
		}
		
		public function flicker(duration:Number = 1):void{
			for each(var obj:FlxBasic in members){
				if (obj is FlxSprite){
					(obj as FlxSprite).flicker(duration);	
				}
				else if (obj is NiloGroup){
					(obj as NiloGroup).flicker(duration);
				}
			}
		}
		
		override public function kill():void{
			super.kill();
			for (var i:uint = 0; i < _colliders.length; i++){
				removeCollider(_colliders[i]);
			}
		}
		
		public function fade(to:Number = 0.0, time:Number = 2):void {
			_fadeTime = 0;
			_fadeTimeTotal = time;
			_alphaDifference = to - _alpha;
			_alpha = to;
			for each (var flxBasic : FlxBasic in members) {
				if (flxBasic is NiloGroup)(flxBasic as NiloGroup).fade(to, time);
			}		
		}
		
		public function decellerateToZero(time:Number):void {
			acceleration = new FlxPoint(-velocity.x / time, -velocity.y / time);
		}
		
		public function set originObject(originObject:FlxSprite):void {
			_refobj = originObject;
		}
		
		/*
		Getters and setters:
		*/
		public function get center():FlxPoint {
			return new FlxPoint((width / 2) + x, (height / 2) + y);
		}
		
		public function set x(X:Number):void {
			_refobj.x = X;
		}
		
		public function get x():Number {
			return _refobj.x;
		}
		
		public function set y(Y:Number):void {
			_refobj.y = Y;
		}
		
		public function get y():Number {
			return _refobj.y;
		}
		
		public function set velocity(velocity:FlxPoint):void {
			_refobj.velocity = velocity;
		}
		
		public function get velocity():FlxPoint {
			return _refobj.velocity;
		}
		
		public function set maxVelocity(velocity:FlxPoint):void {
			_refobj.maxVelocity = velocity;
		}
		
		public function get maxVelocity():FlxPoint {
			return _refobj.maxVelocity;
		}
		
		public function set acceleration(acceleration:FlxPoint):void {
			_refobj.acceleration = acceleration;
		}
		
		public function get acceleration():FlxPoint {
			return _refobj.acceleration;
		}
		
		
		
	}
}
